<!DOCTYPE html>
<html lang="en">
    <head>
  <!-- 元数据 -->
  <meta charset="utf-8">
  <link rel="icon" href="https://gitee.com/cuishikang/tmp/raw/master/img/boke.png">
  <title>续签token的流程 | 小崔的博客</title>
  <meta name="author" content="cuishikang" />
  <meta http-equiv="Cache-Control" content="no-transform" />
  <meta http-equiv="Cache-Control" content="no-siteapp" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="robots" content="index,follow" />
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <meta name="format-detection" content="telphone=no, email=no" />
  
    <meta name="keywords" content="axios, token续签" />
  
  <meta name="description" content="::: tip 介绍 axios请求拦截器 自动续签用户的token:::">
<meta property="og:type" content="article">
<meta property="og:title" content="续签token的流程">
<meta property="og:url" content="https://cuishikang.gitee.io/2022/01/09/Vue_RBAC/2_login_token/index.html">
<meta property="og:site_name" content="小崔的博客">
<meta property="og:description" content="::: tip 介绍 axios请求拦截器 自动续签用户的token:::">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://gitee.com/cuishikang/tmp/raw/master/img/boke.png">
<meta property="article:published_time" content="2022-01-08T16:00:00.000Z">
<meta property="article:modified_time" content="2022-02-19T10:22:58.548Z">
<meta property="article:author" content="cuishikang">
<meta property="article:tag" content="axios">
<meta property="article:tag" content="token续签">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/cuishikang/tmp/raw/master/img/boke.png">
<meta name="twitter:site" content="@null">
  
  <!-- 站点验证相关 -->
  
    
    
    
  
  <!-- 样式表文件 -->
  <link rel="stylesheet" id="kratos-css" href="/css/kratosr.min.css" type="text/css" media="all">
  
    <link rel="stylesheet" id="highlight-css" href="/css/highlight/night-eighties.min.css" type="text/css" media="all">
  
  
  <link rel="stylesheet" id="fontawe-css" href="https://unpkg.com/font-awesome@4.7.0/css/font-awesome.min.css" type="text/css" media="all">
  <link rel="stylesheet" id="nprogress-css" href="https://unpkg.com/nprogress@0.2.0/nprogress.css" type="text/css" media="all">
  
  
    <link rel="stylesheet" href="https://unpkg.com/aplayer@1.10.1/dist/APlayer.min.css">
  
  
    <link rel="stylesheet" href="https://unpkg.com/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css">
  
  
    <link rel="stylesheet" id="darkmode-css" href="/css/kr-dark.min.css" type="text/css" media="all">
  
  <!-- 不得不预先加载的一些JS文件 -->
  <script src="https://unpkg.com/jquery@3.6.0/dist/jquery.min.js"></script>
  
    <script src="https://unpkg.com/qrcode_js@1.0.0/qrcode.min.js"></script>
  
  
  <style>
    
      .kratos-cover.kratos-cover-2 {
        background-image: url('/images/banner.webp');
      }
    
    
      @media(min-width:768px) {
        body.custom-background {
          background-image: url('/images/bg.webp');
        }
      }
    
  </style>
  
<meta name="generator" content="Hexo 6.0.0"></head>


    <body class="custom-background">
        <div id="kratos-wrapper">
    <div id="kratos-page">
        <div id="kratos-header">
            <header id="kratos-desktop-topnav" class="kratos-topnav">
                <div class="container">
                    <div class="nav-header">
                        <nav id="kratos-menu-wrap">
                            <ul id="kratos-primary-menu" class="sf-menu">
                                
                                    
                                        <li><a href="/"><i class="fa fa-home"></i>首页</a></li>
                                    
                                
                                    
                                        <li><a href="/archives/"><i class="fa fa-file"></i>档案馆</a></li>
                                    
                                
                                    
                                        <li><a href="/friends/"><i class="fa fa-paw"></i>好伙伴</a></li>
                                    
                                
                                    
                                        <li>
                                            <a><i class="fa fa-link"></i>关于本人</a>
                                            <ul class="sub-menu">
                                                
                                                    
                                                
                                                    
                                                        <li><a target="_blank" rel="noopener" href="https://gitee.com/cuishikang"><i class="fa fa-git"></i>码云</a></li>
                                                    
                                                
                                                    
                                                        <li><a target="_blank" rel="noopener" href="https://gitee.com/cuishikang/tmp/raw/master/img/2201645358312_.pic.jpg"><i class="fa fa-weixin"></i>微信</a></li>
                                                    
                                                
                                                    
                                                        <li><a target="_blank" rel="noopener" href="https://www.zhihu.com/people/fu-xi-ting-67-17-5"><i class="fa  fa-search"></i>知乎</a></li>
                                                    
                                                
                                                    
                                                        <li><a href="http://cuishikang.gitee.io/my_resume/#/"><i class="fa  fa-file-o"></i>简历</a></li>
                                                    
                                                
                                            </ul>
                                        </li>
                                    
                                
                            </ul>
                        </nav>
                    </div>
                </div>
            </header>
            <header id="kratos-mobile-topnav" class="kratos-topnav">
                <div class="container">
                    <div class="color-logo"><a href="/">小崔的博客</a></div>
                    <div class="nav-toggle">
                        <a class="kratos-nav-toggle js-kratos-nav-toggle">
                            <i></i>
                        </a>
                    </div>
                </div>
            </header>
        </div>
        <div class="kratos-start kratos-hero-2">
            <!-- <div class="kratos-overlay"></div> -->
            <div class="kratos-cover kratos-cover-2 text-center">
                <div class="desc desc2 animate-box">
                    <a href="/">
                        <h2>小崔的博客</h2> <br />
                        <span></span>
                    </a>
                </div>
            </div>
        </div>

        <div id="kratos-blog-post">
            <div class="container">
                <div id="main" class="row">
                    

        

            <section class="col-md-8">

        

            <article>
    <div class="kratos-hentry kratos-post-inner clearfix">
        <header class="kratos-entry-header">
            
                <h1 class="kratos-entry-title text-center">续签token的流程</h1>
            
            
            <ul class="kratos-post-meta text-center">
                <li><i class="fa fa-calendar"></i> 2022-01-09</li>
                <li><i class="fa fa-user"></i> 作者 cuishikang</li>
                <li>
                    <i class="fa fa-edit"></i> 
                    
                    
                        ~8.47K
                    
                    字
                </li>
                
            </ul>
        </header>
        <div class="kratos-post-content">
            <div id="expire-alert" class="alert alert-warning hidden" role="alert">
                本文最后编辑于 <time datetime="1645266178548"></time> 前，其中的内容可能需要更新。
            </div>
            
            <hr />
            <p>::: tip 介绍</p>
<p>axios请求拦截器 自动续签用户的token<br><br>:::</p>
<span id="more"></span>

<h2 id="token续签两种实现方式"><a href="#token续签两种实现方式" class="headerlink" title="token续签两种实现方式"></a>token续签两种实现方式</h2><ul>
<li>token续签有两种方式 其实全部的token续签都涉及到了axios的请求拦截器<code>response.use()</code> 通过请求拦截器去实现token的续签 <ul>
<li><font color =#ff3040>注意: 如果你把token的续签根据(<code>ReFresh_token或者token过期时间戳</code>)储存到session中那么页面关闭后会自动销毁 也就不具备续签性了</font> (刷新不会)</li>
</ul>
</li>
<li>通常都会在<code>utils</code>里的<code>request.js</code>中进行续签处理 (二次封装axios文件)</li>
</ul>
<h2 id="双token续签机制"><a href="#双token续签机制" class="headerlink" title="双token续签机制"></a>双token续签机制</h2><ul>
<li>双token续签机制 是双token <code>ReFresh_token</code> 和 <code>用户token</code> 当<code>用户token</code>过期后 拿<code>ReFresh_token</code>去续签 <code>ReFresh_token</code>一般有效期是半年 该token不具备任何数据 只是作为续签凭证 如果<code>ReFresh_token</code>过期了 就需要重新登录了 这种方式是相对安全的 因为<code>用户token</code>时间只有五分钟 </li>
<li>双token续签机制 总流程图</li>
</ul>
<p><img src="https://jinyanlong-1305883696.cos.ap-hongkong.myqcloud.com/VaQ6uA7POdc8qJv.png" alt="image-20210605115451235"></p>
<ul>
<li>token分为两种<ul>
<li><code>token</code> 普通的token 用于访问需要身份验证的普通接口 获取数据 (一般有效期2小时)</li>
<li><code>refresh_token</code> 续签token 如果普通的token失效了 需要用这个续签 如果两者都失效 需要重新登陆(一般有效期为14天)</li>
</ul>
</li>
<li>token续签 前端流程总结：<ol>
<li>判断token是否失效，如果失效换取新的token（根据refresh_token）</li>
<li>把新的token覆盖到缓存中</li>
<li>重新发送请求调用刚才出错的地址</li>
<li>处理refresh_token失效的情况（失效后跳转到登录页面）</li>
</ol>
</li>
<li><big>注意: </big> token续签需要用到 使用<code>axios.create(&#123;&#125;)</code>  不影响其他功能 单独配置续签地址</li>
</ul>
<blockquote>
<p>续签token代码 <code>utils文件夹 request.js</code> 路由工具文件下  引入在 单独配置登录<code>api文件下</code>的<code>login.js</code> </p>
</blockquote>
<ul>
<li>&#x2F;&#x2F;~ 注释为 token续签过程注释</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//~ 导入 axios组件</span></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"><span class="comment">//~ 导入 router组件 调用跳转方法</span></span><br><span class="line"><span class="keyword">import</span> router <span class="keyword">from</span> <span class="string">&#x27;../router/index&#x27;</span></span><br><span class="line"><span class="comment">// ~ 目标: (1) 续签token (2) 如果refresh_token失效 就认为登录过期 需要重新登录 try&#123;&#125; catch&#123;&#125;</span></span><br><span class="line"><span class="comment">// ~ 双token机制 :</span></span><br><span class="line"><span class="comment">// ~ 一个 token为获取数据token(保质期短 需要续签)</span></span><br><span class="line"><span class="comment">// ~ 一个是配合续签的token(不支持获取数据 只能续签 保质期长)</span></span><br><span class="line"><span class="comment">// ~ 1. 续签token 设置axios.create(&#123;&#125;) 设置axios分支</span></span><br><span class="line"><span class="comment">// ~ axios.create(&#123;&#125;)分支可以设置多个基础url地址</span></span><br><span class="line"><span class="comment">// ~ 2. 声明一个通用的url基础地址 用于申请token的基础路径 用常量保存</span></span><br><span class="line"><span class="keyword">const</span> baseURL = <span class="string">&#x27;http://api-toutiao-web.itheima.net/app/&#x27;</span></span><br><span class="line"><span class="comment">// ~ 3. axios分支的方法 创建axios接口调用方法 取代单一的axios方法(方便单独设置)</span></span><br><span class="line"><span class="keyword">const</span> instance = axios.<span class="title function_">create</span>(&#123;</span><br><span class="line">  <span class="comment">// ~ baseURL是axios属性 用来声明url基础路径</span></span><br><span class="line">  <span class="attr">baseURL</span>: baseURL</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 封装通用的接口调用方法</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> (options) =&gt; &#123;</span><br><span class="line">  <span class="comment">// 这里的返回值是Promise实例对象</span></span><br><span class="line">  <span class="keyword">return</span> <span class="title function_">instance</span>(&#123;</span><br><span class="line">    <span class="comment">// 设置请求方式</span></span><br><span class="line">    <span class="attr">method</span>: options.<span class="property">method</span> || <span class="string">&#x27;GET&#x27;</span>,</span><br><span class="line">    <span class="comment">// 设置请求地址</span></span><br><span class="line">    <span class="attr">url</span>: options.<span class="property">url</span>,</span><br><span class="line">    <span class="comment">// POST/PUT请求参数（请求体）</span></span><br><span class="line">    <span class="attr">data</span>: options.<span class="property">data</span>,</span><br><span class="line">    <span class="comment">// GET请求参数（自动拼接到url地址中）</span></span><br><span class="line">    <span class="attr">params</span>: options.<span class="property">params</span>,</span><br><span class="line">    <span class="comment">// 设置请求头</span></span><br><span class="line">    <span class="attr">headers</span>: options.<span class="property">headers</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 添加响应拦截器 (加工后)</span></span><br><span class="line"><span class="comment">// 响应截拦器是接收到数据 进行一些操作</span></span><br><span class="line"><span class="comment">// 请求结果返回后，先不直接导出，而是先对响应码等等进行处理，处理好后再导出给页面</span></span><br><span class="line"><span class="comment">// response获取的是 axios处理后的数据</span></span><br><span class="line"><span class="comment">// ?  1.常用于清除axios自带data 方便操作</span></span><br><span class="line">instance.<span class="property">interceptors</span>.<span class="property">response</span>.<span class="title function_">use</span>(<span class="keyword">function</span> (<span class="params">response</span>) &#123; <span class="comment">// 获取数据成功时候</span></span><br><span class="line">  <span class="comment">// 当获取数据成功时候 直接进入axios里的data</span></span><br><span class="line">  <span class="keyword">return</span> response.<span class="property">data</span></span><br><span class="line">&#125;, <span class="keyword">async</span> <span class="keyword">function</span> (<span class="params">error</span>) &#123; <span class="comment">// ~ 4. 通常要用async函数还获取新token值(省去then步骤)</span></span><br><span class="line">  <span class="comment">// ~ 开始进行续签token</span></span><br><span class="line">  <span class="comment">// ~ 5. 判断token是否失效 错误参数是error</span></span><br><span class="line">  <span class="comment">// ~ error里面参数response里面status是服务器返回值401(401无权限访问)</span></span><br><span class="line">  <span class="keyword">if</span> (error.<span class="property">response</span>.<span class="property">status</span> === <span class="number">401</span>) &#123;</span><br><span class="line">    <span class="comment">// ~ 6. 如果refresh_token 是有效的 续签token </span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="comment">// ~ 7. 如果token失效了 申请一个新的token(根据 refresh_token)</span></span><br><span class="line">    <span class="comment">// ~ 8. 调用浏览器储存的token (主要用 refresh_token)</span></span><br><span class="line">      <span class="keyword">const</span> user = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(sessionStorage.<span class="title function_">getItem</span>(<span class="string">&#x27;mytoken&#x27;</span>) || <span class="literal">null</span>)</span><br><span class="line">      <span class="comment">// ~ 9. 调用接口 用refresh_token 跟服务器比对 如果成功 续签token</span></span><br><span class="line">      <span class="keyword">const</span> info = <span class="keyword">await</span> <span class="title function_">axios</span>(&#123;</span><br><span class="line">      <span class="comment">// ~ 10. 设置续签token的请求方式 (put请求方式 替换修改的所有数据)</span></span><br><span class="line">        <span class="attr">method</span>: <span class="string">&#x27;put&#x27;</span>,</span><br><span class="line">        <span class="comment">// ~ 11. 设置续签token的地址 基础url+token地址</span></span><br><span class="line">        <span class="attr">url</span>: baseURL + <span class="string">&#x27;v1_0/authorizations&#x27;</span>,</span><br><span class="line">        <span class="attr">headers</span>: &#123;</span><br><span class="line">        <span class="comment">// ~ 12. 设置请求头 携带refresh_token 和服务器进行比对 如果成功 续签新token</span></span><br><span class="line">          <span class="title class_">Authorization</span>: <span class="string">&#x27;Bearer &#x27;</span> + user.<span class="property">refresh_token</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="comment">// ~ 13. 获取最新的token数据 覆盖user里面的原先的失效token (在data.data里面的token)</span></span><br><span class="line">      user.<span class="property">token</span> = info.<span class="property">data</span>.<span class="property">data</span>.<span class="property">token</span></span><br><span class="line">      <span class="comment">// ~ 14. 在浏览器中缓存中保存新获取的token值</span></span><br><span class="line">      sessionStorage.<span class="title function_">setItem</span>(<span class="string">&#x27;mytoken&#x27;</span>, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(user))</span><br><span class="line">      <span class="comment">// ~ 15. 重新调用刚才接口 用新token访问服务器 实现续签成功</span></span><br><span class="line">      <span class="comment">// ~ error是返回错误值的参数 config是错误参数中的属性名 里面包含url地址 请求方式等 相当于重新请求服务器</span></span><br><span class="line">      <span class="keyword">return</span> <span class="title function_">instance</span>(error.<span class="property">config</span>) <span class="comment">// ~ return 如果数据正确就返回去 不打印下面打印信息</span></span><br><span class="line">      <span class="comment">// ~ 16. 如果refresh_token失效 让其重新登录 账号获取新的refresh_token (状态码403)</span></span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="comment">// ~ 17. refresh_token失效 让其返回登录页面(需要调用router 组件 利用router方法跳转)</span></span><br><span class="line">      <span class="keyword">return</span> router.<span class="title function_">push</span>(<span class="string">&#x27;/login&#x27;</span>) <span class="comment">// ~ 让其跳转到首页 return返回数据 不让其执行下面错误提示</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(error)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h2 id="单token时间戳续签机制"><a href="#单token时间戳续签机制" class="headerlink" title="单token时间戳续签机制"></a>单token时间戳续签机制</h2><ul>
<li><p>单token时间戳续签机制 是企业常用的 单<code>用户token</code> 当用户登录的时候 接口会返回一个<code>token过期时间戳</code> 前端把时间戳储存session中 每当请求接口的时候 需要电脑当前时间去计算后端返回<code>token过期时间戳</code> 如果小于10分钟(或者其他) 就会进行续签操作 替换一个新的<code>用户token</code>并且更新<code>token过期时间戳</code> 这种方式相对后端来说简单 安全性不如第一种 因为<code>用户token</code> 有效期通常为8小时甚至更长 因为后端是不会把过期token续签的 所以时间设置太短的话 用户临时不操作就会过期重新登录</p>
</li>
<li><p>单token时间戳续签 总流程图</p>
<p><img src="https://jinyanlong-1305883696.cos.ap-hongkong.myqcloud.com/image-20220111163947060.png" alt="image-20220111163947060"></p>
</li>
</ul>
<blockquote>
<p>后端接口数据需求</p>
</blockquote>
<ul>
<li>前端需要给后端传递旧token即可 后端就会返回一个新的token 和 新的过期时间戳</li>
</ul>
<ol>
<li>第一步在<code>utils</code>文件夹下创建cookie 或者 session方法</li>
</ol>
<p><img src="https://jinyanlong-1305883696.cos.ap-hongkong.myqcloud.com/image-20220111170221100.png" alt="image-20220111170221100"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">Cookies</span> <span class="keyword">from</span> <span class="string">&#x27;js-cookie&#x27;</span></span><br><span class="line"><span class="comment">// cookie命名</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">TokenKey</span> = <span class="string">&#x27;Admin-Token&#x27;</span></span><br><span class="line"><span class="comment">// session命名</span></span><br><span class="line"><span class="keyword">const</span> timeKey = <span class="string">&#x27;expireTime&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取cookie</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">getToken</span> () &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="title class_">Cookies</span>.<span class="title function_">get</span>(<span class="title class_">TokenKey</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 保存cookie</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">setToken</span> (token) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="title class_">Cookies</span>.<span class="title function_">set</span>(<span class="title class_">TokenKey</span>, token)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 移除cookie</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">removeToken</span> () &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="title class_">Cookies</span>.<span class="title function_">remove</span>(<span class="title class_">TokenKey</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 清空sessionStorage</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">clearStorage</span> () &#123;</span><br><span class="line">  <span class="keyword">return</span> sessionStorage.<span class="title function_">clear</span>()</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 设置token过期时间 (保存token过期和当前时间进行比较 低于10分钟(或其他时间)进行续签)</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">setTokenTime</span> (time) &#123;</span><br><span class="line">  <span class="keyword">return</span> sessionStorage.<span class="title function_">setItem</span>(timeKey, time)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 重置token过期时间 (清空token不需要设置为&#x27;&#x27; 或者null 防止无法判断 需要设置为0或-1)</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">removeTokenTime</span> () &#123;</span><br><span class="line">  <span class="keyword">return</span> sessionStorage.<span class="title function_">setItem</span>(timeKey, <span class="number">0</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 获取储存的token的时间</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">getTokenTime</span> () &#123;</span><br><span class="line">  <span class="keyword">return</span> sessionStorage.<span class="title function_">getItem</span>(timeKey)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>第二步创建一个续签token的api接口 <code>api</code>文件夹</li>
</ol>
<blockquote>
<p>续签token的数据结构</p>
</blockquote>
<ul>
<li>续签token的数据结构: <a target="_blank" rel="noopener" href="https://jinyanlong-1305883696.cos.ap-hongkong.myqcloud.com/%E7%BB%AD%E7%AD%BEtoken%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.json">续签token的数据结构json</a></li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// token续签</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">refreshTokenApi</span> (parm) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">await</span> http.<span class="title function_">post</span>(<span class="string">&#x27;/api/sysUser/refreshToken&#x27;</span>, parm)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol start="3">
<li>第三步在axios二次封装下的截器去实现token的续签 <ul>
<li><font color =#ff3040>注意: token续签的处理需要写在添加请求头的上面(把token塞到请求头里) 因为我们在续签后就已经处理了</font></li>
</ul>
</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"><span class="comment">// 导入vuex</span></span><br><span class="line"><span class="keyword">import</span> store <span class="keyword">from</span> <span class="string">&#x27;@/store&#x27;</span></span><br><span class="line"><span class="comment">// 处理token和cookie</span></span><br><span class="line"><span class="keyword">import</span> &#123; getToken, getTokenTime, setTokenTime, removeTokenTime, setToken, clearStorage, removeToken &#125; <span class="keyword">from</span> <span class="string">&#x27;@/utils/auth&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; refreshTokenApi &#125; <span class="keyword">from</span> <span class="string">&#x27;@/api/user&#x27;</span></span><br><span class="line"><span class="comment">// create an axios instance</span></span><br><span class="line"><span class="keyword">const</span> service = axios.<span class="title function_">create</span>(&#123;</span><br><span class="line">  <span class="attr">baseURL</span>: process.<span class="property">env</span>.<span class="property">VUE_APP_BASE_API</span>, <span class="comment">// url = base url + request url</span></span><br><span class="line">  <span class="comment">// withCredentials: true, // send cookies when cross-domain requests</span></span><br><span class="line"> <span class="comment">// timeout: 5000 // request timeout</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">//! --------------------处理token续签</span></span><br><span class="line"><span class="comment">// token续签方法</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">reFresh</span> () &#123;</span><br><span class="line">  <span class="comment">// 声明一个变量 储存当前token 作为替换凭证</span></span><br><span class="line">  <span class="keyword">const</span> parm = &#123;</span><br><span class="line">    <span class="string">&#x27;token&#x27;</span>: <span class="title function_">getToken</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 向接口请求一个新的token</span></span><br><span class="line">  <span class="keyword">return</span> <span class="title function_">refreshTokenApi</span>(parm).<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> res</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="comment">// 这里其实可以简写</span></span><br><span class="line">  <span class="comment">//  return refreshTokenApi(parm).then(res =&gt; res)</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//! 处理token续签</span></span><br><span class="line"><span class="comment">// 定义一个状态位 防止多次获取 无需每个接口都请求</span></span><br><span class="line"><span class="keyword">let</span> isReFresh = <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// request interceptor</span></span><br><span class="line"><span class="comment">// 发送请求之前的拦截器</span></span><br><span class="line">service.<span class="property">interceptors</span>.<span class="property">request</span>.<span class="title function_">use</span>(</span><br><span class="line">  <span class="function"><span class="params">config</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">//! 处理token续签</span></span><br><span class="line">    <span class="comment">// 获取当前系统时间戳</span></span><br><span class="line">    <span class="keyword">const</span> curent = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getTime</span>()</span><br><span class="line">    <span class="comment">// 获取缓存中的时间戳</span></span><br><span class="line">    <span class="keyword">const</span> expireTime = <span class="title function_">getTokenTime</span>()</span><br><span class="line">    <span class="comment">// 如果缓存中的时间戳存在</span></span><br><span class="line">    <span class="keyword">if</span> (expireTime &gt; <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> minMx = (expireTime - curent) / <span class="number">1000</span> / <span class="number">60</span> <span class="comment">// 毫秒计算</span></span><br><span class="line">      <span class="comment">// 判断token时间是否小于十分钟 小于十分钟进行token续签操作</span></span><br><span class="line">      <span class="keyword">if</span> (minMx &lt; <span class="number">10</span>) &#123;</span><br><span class="line">        <span class="comment">// 判断状态位 为false执行 防止多次请求token续签接口</span></span><br><span class="line">        <span class="keyword">if</span> (!isReFresh) &#123;</span><br><span class="line">          isReFresh = <span class="literal">true</span></span><br><span class="line">          <span class="comment">// 返回操作 不再执行以下拦截器操作 防止报错</span></span><br><span class="line">          <span class="keyword">return</span> <span class="title function_">reFresh</span>().<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="comment">// 判断是否请求成功</span></span><br><span class="line">            <span class="keyword">if</span> (res.<span class="property">code</span> == <span class="number">200</span>) &#123;</span><br><span class="line">              <span class="comment">// 设置新的token</span></span><br><span class="line">              <span class="title function_">setToken</span>(res.<span class="property">data</span>.<span class="property">token</span>)</span><br><span class="line">              <span class="comment">// 设置新的时间戳</span></span><br><span class="line">              <span class="title function_">setTokenTime</span>(res.<span class="property">data</span>.<span class="property">expireTime</span>)</span><br><span class="line">              <span class="comment">// 把新的token添加到头部 实现正常获取数据</span></span><br><span class="line">              config.<span class="property">headers</span>[<span class="string">&#x27;token&#x27;</span>] = <span class="title function_">getToken</span>()</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 返回config 正常获取接口数据</span></span><br><span class="line">            <span class="keyword">return</span> config</span><br><span class="line">          &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="comment">// 如果续签失败进行处理(没有)</span></span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(res)</span><br><span class="line">          &#125;).<span class="title function_">finally</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="comment">// 无论是否获取成功或者失败 都需要把状态位重置</span></span><br><span class="line">            isReFresh = <span class="literal">false</span></span><br><span class="line">          &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// do something before request is sent</span></span><br><span class="line">    <span class="comment">// 从store里面获取token，如果token存在，</span></span><br><span class="line">    <span class="comment">// 把token添加到请求的头部Headers里面</span></span><br><span class="line">    <span class="keyword">if</span> (store.<span class="property">getters</span>.<span class="property">token</span>) &#123;</span><br><span class="line">      <span class="comment">// let each request carry token</span></span><br><span class="line">      <span class="comment">// [&#x27;X-Token&#x27;] is a custom headers key</span></span><br><span class="line">      <span class="comment">// please modify it according to the actual situation</span></span><br><span class="line">      <span class="comment">// 把token添加到请求的头部</span></span><br><span class="line">      <span class="comment">//! config是发送的数据 headers是axios请求头 Authorization是后端接口判断token的属性名</span></span><br><span class="line">        config.<span class="property">headers</span>[<span class="string">&#x27;token&#x27;</span>] = <span class="title function_">getToken</span>()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> config</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// do something with request error</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(error) <span class="comment">// for debug</span></span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(error)</span><br><span class="line">  &#125;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>


        </div>
        
            <div class="kratos-copyright text-center clearfix">
                <h5>本作品采用 <a rel="license nofollow" target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/">知识共享署名-相同方式共享 4.0 国际许可协议</a> 进行许可</h5>
            </div>
        
        <footer class="kratos-entry-footer clearfix">
            
                <div class="post-like-donate text-center clearfix" id="post-like-donate">
                
                
                    <a class="share" href="javascript:;"><i class="fa fa-share-alt"></i> 分享</a>
                    <div class="share-wrap" style="display: none;">
    <div class="share-group">
        <a href="javascript:;" class="share-plain qq" onclick="share('qq');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-qq"></i>
            </div>
        </a>
        <a href="javascript:;" class="share-plain qzone" onclick="share('qzone');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-star"></i>
            </div>
        </a>
        <a href="javascript:;" class="share-plain weixin pop style-plain" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-weixin"></i>
            </div>
            <div class="share-int">
                <div class="qrcode" id="wechat-qr"></div>
                <p>打开微信“扫一扫”，打开网页后点击屏幕右上角分享按钮</p>
            </div>
        </a>
        <a href="javascript:;" class="share-plain weibo" onclick="share('weibo');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-weibo"></i>
            </div>
        </a>
        <a href="javascript:;" class="share-plain facebook style-plain" onclick="share('facebook');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-facebook"></i>
            </div>
        </a>
        <a href="javascript:;" class="share-plain twitter style-plain" onclick="share('twitter');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-twitter"></i>
            </div>
        </a>
    </div>
    <script type="text/javascript">
        $(()=>{
            new QRCode("wechat-qr", {
                text: "https://cuishikang.gitee.io/2022/01/09/Vue_RBAC/2_login_token/",
                width: 150,
                height: 150,
                correctLevel : QRCode.CorrectLevel.H
            });
        });
        function share(dest) {
            const qqBase        = "https://connect.qq.com/widget/shareqq/index.html?";
            const weiboBase     = "https://service.weibo.com/share/share.php?";
            const qzoneBase     = "https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?";
            const facebookBase  = "https://www.facebook.com/sharer/sharer.php?";
            const twitterBase   = "https://twitter.com/intent/tweet?";
            const hostUrl       = "https://cuishikang.gitee.io/2022/01/09/Vue_RBAC/2_login_token/";
            const title         = "「续签token的流程」";
            const excerpt       = `::: tip 介绍
axios请求拦截器 自动续签用户的token:::`;
            let _URL;
            switch (dest) {
                case "qq"       : _URL = qqBase+"url="+hostUrl+"&title="+title+"&desc=&summary="+excerpt+"&site=cxpy";     break;
                case "weibo"    : _URL = weiboBase+"url="+hostUrl+"&title="+title+excerpt;                                 break;
                case "qzone"    : _URL = qzoneBase+"url="+hostUrl+"&title="+title+"&desc=&summary="+excerpt+"&site=cxpy";  break;
                case "facebook" : _URL = facebookBase+"u="+hostUrl;                                                        break;
                case "twitter"  : _URL = twitterBase+"text="+title+excerpt+"&url="+hostUrl;                                break;
            }
            window.open(_URL);
        };
    </script>
</div>
                
                </div>
            
            <div class="footer-tag clearfix">
                <div class="pull-left">
                <i class="fa fa-tags"></i>
                    <a class="tag-none-link" href="/tags/axios/" rel="tag">axios</a>, <a class="tag-none-link" href="/tags/token%E7%BB%AD%E7%AD%BE/" rel="tag">token续签</a>
                </div>
                <div class="pull-date">
                <span>最后编辑：2022-02-19</span>
                </div>
            </div>
        </footer>
    </div>
    
        <nav class="navigation post-navigation clearfix" role="navigation">
            
            <div class="nav-previous clearfix">
                <a title=" Vue登录样式" href="/2021/12/13/Vue_style/1.6_vue_login/">&lt; 上一篇</a>
            </div>
            
            
            <div class="nav-next clearfix">
                <a title=" RABC权限学习记录文档" href="/2022/01/11/Vue_RBAC/1_RBAC/">下一篇 &gt;</a>
            </div>
            
        </nav>
    
    
</article>

        

            </section>

        

                
            

<section id="kratos-widget-area" class="col-md-4 hidden-xs hidden-sm">
    <!-- 文章和页面根据splitter来分割，没有的话就从头开始设置为sticky -->
    
    
                <aside id="krw-about" class="widget widget-kratos-about clearfix">
    <div class="photo-background"></div>
    <div class="photo-wrapper clearfix">
        <div class="photo-wrapper-tip text-center">
            <img class="about-photo" src="https://gitee.com/cuishikang/tmp/raw/master/img/20220220194141.png" />
        </div>
    </div>
    <div class="textwidget">
        <p class="text-center"></p>
    </div>
    <div class="site-meta">
        <a class="meta-item" href="/archives/">
            <span class="title">
                文章
            </span>
            <span class="count">
                91
            </span>
        </a>
        <a class="meta-item" href="/categories/">
            <span class="title">
                分类
            </span>
            <span class="count">
                13
            </span>
        </a>
        <a class="meta-item" href="/tags/">
            <span class="title">
                标签
            </span>
            <span class="count">
                33
            </span>
        </a>
    </div>
</aside>
            
                    <div class="sticky-area">
                
                
  <aside id="krw-categories" class="widget widget-kratos-categories clearfix">
    <h4 class="widget-title"><i class="fa fa-folder"></i>分类目录</h4>
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Css/">Css</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaScript/">JavaScript</a><span class="category-list-count">15</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/RABC/">RABC</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Vscode/">Vscode</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Vue/">Vue</a><span class="category-list-count">13</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Vue3/">Vue3</a><span class="category-list-count">25</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Vue%E7%A7%BB%E5%8A%A8%E5%A4%B4%E6%9D%A1%E9%A1%B9%E7%9B%AE/">Vue移动头条项目</a><span class="category-list-count">10</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/animation/">animation</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/axios/">axios</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/other/">other</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/uniapp/">uniapp</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/vue-element-admin/">vue-element-admin</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B0%8F%E7%A8%8B%E5%BA%8F/">小程序</a><span class="category-list-count">2</span></li></ul>
  </aside>


            
                
  <aside id="krw-tags" class="widget widget-kratos-tags clearfix">
    <h4 class="widget-title"><i class="fa fa-tags"></i>标签聚合</h4>
      <div class="tag-clouds">
        <a href="/tags/Css/" style="font-size: 0.66em;">Css</a> <a href="/tags/H5Video/" style="font-size: 0.6em;">H5Video</a> <a href="/tags/JavaScript/" style="font-size: 0.74em;">JavaScript</a> <a href="/tags/My-project/" style="font-size: 0.6em;">My project</a> <a href="/tags/QQ/" style="font-size: 0.6em;">QQ</a> <a href="/tags/RABC/" style="font-size: 0.6em;">RABC</a> <a href="/tags/Vant/" style="font-size: 0.71em;">Vant</a> <a href="/tags/VeeValidate/" style="font-size: 0.6em;">VeeValidate</a> <a href="/tags/Vscode/" style="font-size: 0.6em;">Vscode</a> <a href="/tags/Vue/" style="font-size: 0.8em;">Vue</a> <a href="/tags/Vue-Router/" style="font-size: 0.6em;">Vue Router</a> <a href="/tags/Vue3/" style="font-size: 0.77em;">Vue3</a> <a href="/tags/Vuex/" style="font-size: 0.6em;">Vuex</a> <a href="/tags/Vue%E7%A7%BB%E5%8A%A8%E7%AB%AF/" style="font-size: 0.74em;">Vue移动端</a> <a href="/tags/Windows/" style="font-size: 0.6em;">Windows</a> <a href="/tags/animation/" style="font-size: 0.63em;">animation</a> <a href="/tags/axios/" style="font-size: 0.69em;">axios</a> <a href="/tags/echarts/" style="font-size: 0.6em;">echarts</a>
      </div>
  </aside>

            
                
  <aside id="krw-posts" class="widget widget-kratos-posts">
  <h4 class="widget-title"><i class="fa fa-file"></i>最新文章</h4>
  <div class="tab-content">
      <ul class="list-group">
        
        
          
          
            <a class="list-group-item" href="/2111/02/19/JavaScript/5_algorithm_tree/"><i class="fa  fa-book"></i> JavaScript树形数据转换算法</a>
            
          
        
          
          
            <a class="list-group-item" href="/2099/01/27/Vue3/1.1.1_Vue_study/"><i class="fa  fa-book"></i> Vue3 学习手册(博客版)</a>
            
          
        
          
          
            <a class="list-group-item" href="/2022/02/28/JavaScript/0.2_scroll/"><i class="fa  fa-book"></i> JS 滚动到指定位置和回到顶部</a>
            
          
        
          
          
            <a class="list-group-item" href="/2022/02/23/Vue/5_Vue_nextTick/"><i class="fa  fa-book"></i> 理解$nextTick</a>
            
          
        
          
          
            <a class="list-group-item" href="/2022/02/20/hello-world/"><i class="fa  fa-book"></i> Hello World</a>
            
          
        
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
          
            
      </ul>
  </div>
  </aside>

            
    </div>
</section>
        
        </div>
    </div>
</div>
<footer>
    <div id="footer"  class="ap-lrc"  >
        <div class="container">
            <div class="row">
                <div class="col-md-6 col-md-offset-3 footer-list text-center">
                    <ul class="kratos-social-icons">
                        
                        
                        <li><a target="_blank" rel="nofollow" href="https://t.me/CandyUnion"><i class="fa fa-telegram"></i></a></li>
                        
                        
                        
                        <li><a target="_blank" rel="me" href="https://nya.one/@Candinya"><i class="fa fa fa-share-alt-square"></i></a></li>
                        <li><a target="_blank" rel="nofollow" href="https://github.com/Candinya"><i class="fa fa-github"></i></a></li>
                        
                    </ul>
                    <ul class="kratos-copyright">
                        <div>
                            <li>&copy; 2022 小崔的博客 版权所有.</li>
                            <li>本站已运行<span id="span_dt">Loading...</span></li>
                        </div>
                        <div>
                            <li>Theme <a href="https://github.com/Candinya/Kratos-Rebirth" target="_blank">Kratos:Rebirth</a></li>
                            <li>Site built with&nbsp;<i class="fa fa-heart throb" style="color:#d43f57"></i>&nbsp;by cuishikang.</li>
                        </div>
                        <div>
                            <li>Powered by <a href="https://hexo.io" target="_blank" rel="nofollow">Hexo</a></li>
                            <li>Hosted on <a href="https://github.io" target="_blank">Github Pages</a></li>
                        </div>
                        <div>
                            
                            
                        </div>
                    </ul>
                </div>
            </div>
        </div>
        <div class="kr-tool text-center">
            <div class="tool">
                
                    <div class="box search-box">
                        <a href="/search/">
                            <span class="fa fa-search"></span>
                        </a>
                    </div>
                
                
                    <div class="box theme-box" id="darkmode-switch">
                        <span class="fa fa-adjust"></span>
                    </div>
                
                
            </div>
            <div class="box gotop-box">
                <span class="fa fa-chevron-up"></span>
            </div>
        </div>
    </div>
</footer>
</div>
</div>

        <script defer src="https://unpkg.com/bootstrap@3.3.4/dist/js/bootstrap.min.js"></script>
<script defer src="https://unpkg.com/nprogress@0.2.0/nprogress.js"></script>
<script>
    if (!window.kr) {
        window.kr = {};
    }
    window.kr.notMobile = (!(navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)));
    window.kr.siteRoot = "/";
</script>


    <script async src="/js/candy.min.js"></script>



    <script defer src="https://unpkg.com/aplayer@1.10.1/dist/APlayer.min.js"></script>
    
    <script defer src="https://unpkg.com/meting@2/dist/Meting.min.js"></script>
    <meting-js
        server="netease"
        type="song"
        id="1375305989"
        order="random"
        fixed="true"
    >
    </meting-js>



    <script defer src="https://unpkg.com/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script>

<script defer src="https://unpkg.com/clipboard@2.0.6/dist/clipboard.min.js"></script>
<script defer src="/js/kratosr.min.js"></script>
<script defer src="/js/pjax.min.js"></script>


    <script defer src="/js/kr-dark.min.js"></script>



<!-- Extra support for third-party plguins  -->


    </body>
</html>